/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Communication Module                           */
/*                                                                           */
/*    Copyright (C) 2007 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    comRFReceiver - Radio frequency receiver                               */
/*                                                                           */
/*    Dependencies:                                                          */
/*      RFRXIsSet()  - must be defined in drvIOConfig.h to read              */
/*                     receiver input pin                                    */
/*      drvRXGeneral - general receiver driver must be implemented           */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <comRFReceiver.h>
#include <drvRXGeneral.h>
#include "sysCompiler.h"
#include "drvIOCOnfig.h"

///////////////////////////////////////////////////////////////////////////////
// Module Local Variables
static dosWord l_time_stamp = 0;							// temporary storage for timestamp
static dosWord l_bit_time = 0;
static dosWord l_data = 0;
static dosWord l_decoded_data = 0;
static dosByte l_bit_average = 0;
static dosByte l_bit_average_counter = 0;
static dosByte l_bit_counter = 0;
static dosByte l_byte_counter = 0;
static dosByte l_status = 0;
static comRFMessage l_message;
static dosBool l_data_received = dosFalse;


// decoding table (DC offset equalized codes)
static dosROM_DATA(dosByte, l_decoding_table)[16] =
{
	0x0B, 0x0D, 0x0E, 0x13, 0x16, 0x19, 0x1A, 0x1C, 0x23, 0x25, 0x26, 0x29, 0x2C, 0x31, 0x32, 0x34
};


///////////////////////////////////////////////////////////////////////////////
// User function prototypes
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Initialize
void comRFRXInit(void)
{
	InitRFRX();
}

///////////////////////////////////////////////////////////////////////////////
// Is Data Received
dosBool comRFRXIsDataReceived(void)
{
	return l_data_received;
}

///////////////////////////////////////////////////////////////////////////////
// Get Received Data
dosBool comRFRXGetReceivedData(comRFMessage* out_message)
{
	dosBool retval = l_data_received;

	l_data_received = dosFalse;
	*out_message = l_message;

	return retval;
}

///////////////////////////////////////////////////////////////////////////////
// PIN changed interrupt callback
void drvRXGENPinChangedCallback( dosWord in_time_stamp )
{
	dosWord time;
	dosWord deviation;

	// check for possible buffer overrun
	if( l_status == 0 && l_data_received )
		return;

	// if preamble, calculate average bit time
	if( l_status <= 11 )
	{
		// if first edge
		if( l_status == 0 )
		{
			// first edge
			l_bit_time = 0;
		}
		else
		{
			// next edges

			// calculate edge length
			time = in_time_stamp - l_time_stamp;

			// check timing criteria
			if( time > comRFRX_BIT_LENGTH + comRFRX_BIT_LENGTH_DEVIATION ||
					time < comRFRX_BIT_LENGTH - comRFRX_BIT_LENGTH_DEVIATION )
			{
				// wrong timing -> cancel reception
				l_status = 0;
				return;
			}

			l_bit_time += time;
		}

		// if last edge of preamble
		if( l_status == 11 )
		{
			// calculate bit length average
			l_bit_time /= 11;

			// init buffers
			l_data = 0;
			l_decoded_data = 0;
			l_bit_average_counter = 0;
			l_bit_counter = 0;
			l_byte_counter = 0;

			// start sampling procedure
			drvRXGENSetTimerCallback( in_time_stamp + 3 * l_bit_time / 2 - comRFRX_BIT_SAMPLING_OFFET ); 
		}
		else
		{
			// timeout
			drvRXGENSetTimerCallback( in_time_stamp + comRFRX_BIT_LENGTH + comRFRX_BIT_LENGTH_DEVIATION ); 
		}

		l_status++;
	}
	else
	{
		// normal bit reception (adjust sample point)

		// check if edge is acceptable
		time = in_time_stamp - l_time_stamp;
		deviation = (time + comRFRX_BIT_LENGTH / 2) / comRFRX_BIT_LENGTH;

		if( deviation < 1 )
			deviation = 1;

		if( deviation > 3 )
			deviation = 3;

		deviation *= comRFRX_BIT_LENGTH_DEVIATION;

		time %= comRFRX_BIT_LENGTH;

		if( time < deviation || time > comRFRX_BIT_LENGTH - deviation )
		{
			// accept edge and adjust timing
			drvRXGENSetTimerCallback( in_time_stamp + l_bit_time / 2 - comRFRX_BIT_SAMPLING_OFFET ); 
		}		
	}

	l_time_stamp = in_time_stamp;
}

///////////////////////////////////////////////////////////////////////////////
// Timer callback function
void drvRXGENTimerCallback(void)
{
	dosByte data;
	dosByte i;

	if( l_status < 12 )
	{
		// timeout occured while receiving preamble
		l_status = 0;
	}
	else
	{
		// repare to receive next packet
		if( l_status == 13 )
		{
			l_status = 0;
			return;
		}

		// sample data bits
		switch( l_bit_average_counter )
		{
			case 0:
				// first sample point
				l_bit_average = RFRXIsSet();
				drvRXGENAddTimerCallback( comRFRX_BIT_SAMPLING_OFFET ); 
				l_bit_average_counter++;
				break;

			case 1:
				// second sample point
				l_bit_average += RFRXIsSet();
				drvRXGENAddTimerCallback( comRFRX_BIT_SAMPLING_OFFET ); 
				l_bit_average_counter++;
				break;

			case 2:
				// third sample point
				l_bit_average += RFRXIsSet();
				l_bit_counter++;
				l_bit_average_counter = 0;

				// check if six bits (one nibble is received )
				if( l_bit_counter ==  7 || l_bit_counter == 13 )
				{
					// find data in the decoding table
					data = 0;
					while( data < 16 && l_data != l_decoding_table[data] )
						data++;

					// if invalid data received
					if( data > 15 )
					{
						l_status = 0;
					}
					else
					{
						// update decoded data
						l_decoded_data <<= 4;
						l_decoded_data += data;

						// if one byte received
						if( l_bit_counter == 13 )
						{
							// first byte received
							if( l_byte_counter == 0 )
							{
								l_message.Id = l_decoded_data >> 3;
								l_message.Length = (l_decoded_data & 0x07) + 1;
							}
							else
							{
								// if checksum received 
								if( l_byte_counter > l_message.Length )
								{
									data = (l_message.Id << 3) + ((l_message.Length - 1) & 0x07);

									for( i = 0; i < l_message.Length; i++ )
										data += l_message.Data[i];

									// if valid data received
									if( data == l_decoded_data )
										l_data_received = dosTrue;

									// prepare to receive next packet
									l_status = 13;
									drvRXGENAddTimerCallback( 2 * l_bit_time ); 
									return;
								}
								else
								{
									// data byte received
									l_message.Data[l_byte_counter-1] = l_decoded_data;
								}
							}

							l_decoded_data = 0;
							l_bit_counter = 1;
							l_byte_counter++;
						}
					}

					l_data = 0;
				}

				l_data <<= 1;
				l_data += l_bit_average / 2;

				// sample next bit
				drvRXGENAddTimerCallback( l_bit_time - 2 * comRFRX_BIT_SAMPLING_OFFET ); 
				break;
		}
	}
}
